package com.tengju.bff.interfaces.shared.servlet;

import com.google.common.collect.Maps;
import com.tengju.support.domain.annotation.BizLog;
import com.tengju.support.domain.annotation.BizLogSysName;
import com.tengju.support.domain.model.bizlog.BizLogContent;
import com.tengju.support.domain.model.bizlog.BizLogMessage;
import com.tengju.support.domain.service.log.BizLogProducer;
import com.tengju.user.domain.model.login.UserType;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @Author: 李大仙
 * @Date: 2021/3/9 9:37 下午
 */
@Component
@Aspect
public class BizLogAction {

    @Autowired
    private BizLogProducer bizLogProducer;
    @Autowired
    private static final Logger logger = LoggerFactory.getLogger(BizLogAction.class);

    @Pointcut("@annotation(com.tengju.support.domain.annotation.BizLog)")
    public void controllerAspect() {
    }

    @Around(value = "controllerAspect() && @annotation(bizlog)")
    public Object around(ProceedingJoinPoint joinPoint, BizLog bizlog) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        try {
            saveLog(joinPoint, result, (end - start), bizlog.sysName());
        } catch (Exception e) {
            logger.error("saveLog error", e);
        }
        return result;
    }

    @Async
    public void saveLog(ProceedingJoinPoint joinPoint, Object result, long time, BizLogSysName sysName) {
        UserServletContext servletContext = ServletContextUtil.getServletContext();
        HttpServletRequest request = servletContext.getRequest();
        Object[] args = joinPoint.getArgs();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        String[] parameterNames = methodSignature.getParameterNames();
        Map<String, Object> argsMap = Maps.newHashMap();
        for (int i = 0; i < args.length; i++) {
            argsMap.put(parameterNames[i], args[i]);
        }
        BizLogMessage bizLogMessage = new BizLogMessage(
                sysName,
                request.getServletPath(),
                BizLogContent.of(argsMap, result, time),
                Optional.ofNullable(servletContext.getRealName()).orElse(""),
                Optional.ofNullable(servletContext.getUserType()).map(UserType::getDesc).orElse(""),
                new Date(),
                servletContext.getIp(),
                new HashMap<>());
        bizLogProducer.sendMessage(bizLogMessage);
    }
}
